/*
 * scan.h - the jam yacc scanner
 *
 * External functions:
 *
 *	yyerror( char *s ) - print a parsing error message
 *	yyfparse( char *s ) - scan include file s
 *	yylex() - parse the next token, returning its type
 *	yymode() - adjust lexicon of scanner
 *	yyparse() - declaration for yacc parser
 *	yyanyerrors() - indicate if any parsing errors occured
 *
 * The yymode() function is for the parser to adjust the lexicon of the
 * scanner.  Aside from normal keyword scanning, there is a mode to
 * handle action strings (look only for the closing }) and a mode to 
 * ignore most keywords when looking for a punctuation keyword.  This 
 * allows non-punctuation keywords to be used in lists without quoting.
 */

#ifndef SCAN_HPP
#define SCAN_HPP

#ifdef _MSC_VER
#pragma once
#endif

#include "jam.hpp"
#include <boost/shared_ptr.hpp>
#include <boost/noncopyable.hpp>
#include <boost/intrusive_ptr.hpp>
#include <iosfwd>
#include <map>

///////////////////////////////////////////////////////////////////////////////////////
////// YYSTYPE - value of a lexical token
///////////////////////////////////////////////////////////////////////////////////////
struct parse_node_base;
typedef boost::intrusive_ptr<parse_node_base> parse_node_ptr;

struct YYSTYPE
{
	int type;	
	parse_node_ptr parse;

	int number;
	jam_string string;
	jam_string file;
	int line;
};

//Scanner mode
enum scan_mode
{
	SCAN_NORMAL,// normal parsing
	SCAN_STRING,// look only for matching }
	SCAN_PUNCT,	// only punctuation keywords
};

//Scanner context
class JAMLIB_EXPORT scan_context : public boost::noncopyable
{
	boost::shared_ptr<std::istream> file_;	//Handle to the current file
	jam_string fname_; //File name
	int line_; //Line counter for error messages

	scan_mode scanmode_;	
	bool debug_mode_,save_comments_;
public:
	typedef std::map<int,jam_string> comment_map_t;
	
	scan_context(const jam_string &name,bool debug_mode=false,
		bool save_comments=false);
	virtual ~scan_context();

	void set_scan_mode(scan_mode scanmode);
	void throw_error(const char *s, const YYSTYPE *yylval);

	void get_input_stream_info(jam_string *name, int *line) const;	
	bool has_more_chars() const;

	int yylex(YYSTYPE *yylval);

	jam_string get_comment(int ln) const;
	const jam_string& get_fname() const { return fname_; }
	const comment_map_t& get_comments() const {return comments_;}

	static bool is_keyword(const jam_string &str);

private:
	comment_map_t comments_;

	int do_eof(YYSTYPE *yylval);
	
	bool get_next_char(char *o);
	void unget_char();
	static void symdump(const YYSTYPE *s, std::ostream &out);
};

#endif //SCAN_HPP
